#!/usr/bin/python
# encoding: utf-8

"""
@file: linear_pro.py
@time: 16/8/27 上午9:37
"""
from itertools import chain
from mathsolver.functions.root.jiefangchenzu import *
from mathsolver.functions.fangcheng.budengshi import FangChenBuDengShi002
from mathsolver.functions.budengshi import common_opers
from sympy import solve, degree, expand, factor, Abs, degree_list
from sympy.core.mul import Mul


# 1.线性约束条件，线性目标函数的范围问题(OK)
# singleTest('已知实数x、y满足\\left\\{\\begin{array}{c}x-4y≤3\\\\5x+3y≤15\\\\x≥1\\end{array}\\right.,则2x+y的最大值为()
# singleTest('已知实数x、y满足\\left\\{\\begin{array}{c}x-4y≤3\\\\5x+3y≤15\\\\x≥1\\end{array}\\right.,则z=2x+y的最大值为()
class LinearProgramming(BaseFunction):
    def solver(self, *args):
        self.label.add('线性规划截距型')
        ineqs = args[0]  # 不等式方程组
        if isinstance(ineqs, BaseIneq):
            ineqs = BaseIneqs([ineqs.sympify()])
        if common_opers.iterable(ineqs):
            ineqs = BaseIneqs(ineqs)
        ineqs = common_opers.i_simp_ineqs(ineqs)  # ineqs = common_opers.simp_ineqs(ineqs)
        symbs = common_opers.ineqs_symbs(ineqs.sympify())
        if len(symbs) > 2:
            raise Exception('Type Match Error')
        if isinstance(args[1], BaseEq):
            target_expr = args[1]  # 目标表达式
        elif common_opers.iterable(args[1]):
            target_expr = BaseEq(args[1])
        else:
            target_expr = BaseEq(["z", args[1].sympify()])
        target_sym, target_right = target_expr.sympify()
        x_symbol, y_symbol = common_opers.x_y_symbols(target_sym - target_right)
        # ineqs_inters = common_opers.ineqs_intersections(ineqs)  # 1.多个约束条件两两组合的交点。[只是求交点，不一定满足可行域]
        # 2.验证交点是否满足不等式组，不满足的扣除。满足不等式的保留。
        satisfied_inters = common_opers.satisfied_ineqs_intersections(ineqs, x_symbol, y_symbol)
        # 3.将交点的横纵坐标分别代入目标函数的x，y求出未知数Z的取值集。即得到z的取值范围。
        target_e_values = list(map(lambda t: (t[0], common_opers.expr_subs(target_right, t[1])), satisfied_inters))
        if len(satisfied_inters) == 1:
            self.steps.append(['由约束条件:', ineqs.printing()])
            self.steps.append(['画出可行域:', ''])
            op_point = zip(
                *sorted(map(lambda s_v: (str(s_v[0]), s_v[1]), satisfied_inters[0][1]), key=lambda s_v: s_v[0]))
            target_text = args[-1] if isinstance(args[-1], str) else str(args[-1])
            op_str = '最大值' if target_text.find('最大值') >= 0 else '最小值'
            self.steps.append(['当%s ' % target_sym, '经过:' + str(op_point[1]) + ' 时取的' + op_str])
            op_value = target_e_values[0][-1]
            self.steps.append([op_str + ' 为', new_latex(op_value)])
            # self.output.append(BaseNumber(op_value))
            self.output.append(BaseSymbolValue({target_sym: op_value}))
            self.label.add('已知含参不等式的解集求不等式')
            return self
        # 4.注意约束条件为开区间时的取值问题。
        min_point = min(target_e_values, key=lambda t: t[1])
        min_point_opened = len(list(filter(lambda ineq: ineq[1] in ('>', '<'), min_point[0]))) > 0
        max_point = max(target_e_values, key=lambda t: t[1])
        max_point_opened = len(list(filter(lambda ineq: ineq[1] in ('>', '<'), max_point[0]))) > 0
        target_interval = common_opers.interval(min_point[1], max_point[1], min_point_opened, max_point_opened)
        # ---------------输出解题步骤--------------------
        self.steps.append(['由约束条件:', ineqs.printing()])
        self.steps.append(['画出可行域:', ''])
        target_expr_slope_eq = common_opers.line_slope_inter_eq(target_expr, x_symbol, y_symbol)
        self.steps.append(['由:%s。' % target_expr.printing(), '得:' + target_expr_slope_eq.printing()])
        slope = common_opers.line_slope(target_expr_slope_eq)
        self.steps.append(
            ['做' + BaseEq([y_symbol, sympify(slope) * sympify(x_symbol)]).printing() + '的平行线截可行域。', ''])
        target_text = args[-1] if isinstance(args[-1], str) else str(args[-1])
        if isinstance(target_interval, FiniteSet):
            tmp_op_value = list(target_interval)[0]
            if target_text.find('最大值') >= 0:
                self.steps.append(['得到%s的最大值为' % target_sym, new_latex(tmp_op_value)])
            elif target_text.find('最小值') >= 0:
                self.steps.append(['得到%s的最小值为' % target_sym, new_latex(tmp_op_value)])
            else:
                self.steps.append(['得到%s的最值为' % target_sym, new_latex(tmp_op_value)])
            return self
        if target_text.find('最大值') >= 0:
            self.steps.append(['得到%s的最大值为' % target_sym, new_latex(target_interval.right)])
            # self.output.append(BaseSymbolValue({sympify(target_sym): target_interval.right}))
            self.output.append(BaseNumber(target_interval.right))
        elif target_text.find('最小值') >= 0:
            self.steps.append(['得到%s的最小值为' % target_sym, new_latex(target_interval.left)])
            # self.output.append(BaseSymbolValue({sympify(target_sym): target_interval.left}))
            self.output.append(BaseNumber(target_interval.left))
        else:
            self.steps.append(['得到%s的取值范围为' % target_sym, new_latex(target_interval)])
            # self.output.append(BaseSymbolValue({sympify(target_sym): target_interval}))
            self.output.append(common_opers.to_base_interval(target_interval))
        return self


# 2.可行域内的点与圆上的点的距离型最值(OK)
class LinearProgrammingDistance(BaseFunction):
    def solver(self, *args):
        self.label.add('可行域内的点与圆上的点的距离型最值')
        ineqs_printing = args[0].printing()
        ineqs = args[0].sympify()  # 不等式方程组
        symbs = common_opers.ineqs_symbs(ineqs)
        if len(symbs) > 2:
            raise Exception('Type Match Error')
        circle_expr = args[1].sympify()  # 圆表达式
        p_sym = args[2].sympify()
        q_sym = args[3].sympify()
        circle_center, r = common_opers.circle_center_and_radius(circle_expr)  # 1.求圆心坐标和半径
        eqs = common_opers.ineqs_2_eqs(ineqs)  # 不等式组对应的等式方程组
        inters = common_opers.lines_intersections(eqs)  # 求等式方程组的所有直线的交点
        satisfied_inters = filter(lambda t: common_opers.satisfied_ineqs(ineqs, t[1]),
                                  inters)  # 2.验证交点是否满足不等式组，不满足的扣除。满足不等式的保留。
        line_eqs = [BaseEq([ineq[0], ineq[2]]) for ineq in ineqs]  # 3.不等式组对应的直线
        per_points = map(lambda line_eq: common_opers.perpendicular_line_and_foot(line_eq, circle_center)[1],
                         line_eqs)  # 4.求圆点到各个直线的垂足
        verify_per_points = filter(
            lambda per_point: common_opers.satisfied_ineqs(ineqs, (('x', per_point[0]), ('y', per_point[1]))),
            per_points)  # 5.保留满足不等式组的垂足
        # -------求圆心到各个直线的垂点及其距离-----------------
        verify_per_point_distances = map(
            lambda per_point: (per_point, common_opers.point_2_point_distance(circle_center, per_point)),
            verify_per_points)
        # verify_per_point_distances = map(lambda d: (zip(*d[0])[-1], d[1]), verify_per_point_distances)
        # verify_per_point_distances = map(lambda d: d[1] - r, verify_per_point_distances)  # 减去半径
        # --------求圆心到各个不等式组交点之间的距离----------------------------
        verify_inter_distances = map(
            lambda line_inter: (line_inter[1], common_opers.point_2_point_distance(circle_center,
                                                                                   map(lambda sv: sv[1],
                                                                                       line_inter[1]))),
            satisfied_inters)
        verify_inter_distances = map(lambda d: (zip(*d[0])[-1], d[1]), verify_inter_distances)
        # verify_inter_distances = map(lambda d: d[1] - r, verify_inter_distances)  # 减去半径

        # ----------求出所有距离的最小值-----------------------------------
        min_distance = min(chain(verify_per_point_distances, verify_inter_distances), key=lambda d: d[1])  # 最小值
        max_distance = max(chain(verify_per_point_distances, verify_inter_distances), key=lambda d: d[1])  # 最大值
        # ---------------------------输出---------------------------
        self.steps.append(['由约束条件:' + ineqs_printing, ''])
        self.steps.append(['得圆心:C' + str(circle_center), ';半径r=' + str(r)])
        pq_sym = '%s%s' % (p_sym, q_sym)
        pm_sym = '%sC' % p_sym
        self.steps.append(['|%s|min=' % pq_sym, '|%s|min - r' % pm_sym])
        self.steps.append(['|%s|max=' % pq_sym, '|%s|max + r' % pm_sym])
        self.steps.append(['由可行域可知:', ''])
        min_len = min_distance[1] - r
        max_len = max_distance[1] + r
        self.steps.append(['|%s|min=' % pq_sym + str(min_distance[1] - r), '此时P:' + str(min_distance[0])])
        self.steps.append(['|%s|max=' % pq_sym + str(max_distance[1] + r), '此时P:' + str(max_distance[0])])
        self.output.append(common_opers.to_base_interval(Interval(sympify(min_len), sympify(max_len))))
        return self


# 已知实数x,y满足\\left\\{\\begin{array}{c}y≥1\\\\x+y-4≤0\\\\x-y≥0\\end{array}\\right.,则x^{2}+y^{2}+4x+6y+14的最大值为()
# 已知实数x,y满足\\left\\{\\begin{array}{c}x+y-3≥0\\\\x+2y-5≤0\\\\y≥0\\end{array}\\right.,则z=(x-1)^{2}+y^{2}的最小值是().
class XianXingGuiHhua001(BaseFunction):
    @staticmethod
    def sqrt_arg(tmp_f):  # 获取含有根号的表达式中 是否含有x**2 + y**2
        d = common_opers.coefficients_dict(tmp_f)
        sqrt_term = filter(lambda i: isinstance(i[0], Pow), d.items())
        if sqrt_term:
            st = sqrt_term[0]
            if st[0].args[1] == sympify('1/2'):
                return st[0].args[0]
        return None

    def solver(self, *args):
        self.label.add('可行域内的点与圆上的点的距离型最值')
        try:
            ineqs_printing = args[0].printing()
            ineqs = args[0].sympify()  # 不等式方程组
        except Exception:
            tmp_ineqs = common_opers.simp_ineqs(args[0])
            ineqs_printing = tmp_ineqs.printing()
            ineqs = tmp_ineqs.sympify()
        # ineqs = args[0].sympify()  # 不等式方程组
        ineq_symbs = common_opers.ineqs_symbs(ineqs)
        if len(ineq_symbs) > 2:
            raise Exception('Type Match Error')
        if isinstance(args[1], BaseEq):
            z_sy, circle_expr = args[1].sympify()
            try:
                circle_expr = XianXingGuiHhua001.sqrt_arg(circle_expr) if XianXingGuiHhua001.sqrt_arg(
                    circle_expr) else circle_expr
            except Exception:
                pass
        else:
            circle_expr = args[1].sympify()  # 圆表达式
            try:
                circle_expr = XianXingGuiHhua001.sqrt_arg(circle_expr) if XianXingGuiHhua001.sqrt_arg(
                    circle_expr) else circle_expr
            except Exception:
                pass
        text = args[2]
        symbs = circle_expr.free_symbols
        # p_sym = args[2].sympify()
        # q_sym = args[3].sympify()
        circle_center, r = common_opers.circle_center_and_radius([circle_expr, 1])  # 1.求圆心坐标和半径
        eqs = common_opers.ineqs_2_eqs(ineqs)  # 不等式组对应的等式方程组
        inters = common_opers.lines_intersections(eqs)  # 求等式方程组的所有直线的交点
        satisfied_inters = filter(lambda t: common_opers.satisfied_ineqs(ineqs, t[1]),
                                  inters)  # 2.验证交点是否满足不等式组，不满足的扣除。满足不等式的保留。
        line_eqs = [BaseEq([ineq[0], ineq[2]]) for ineq in ineqs]  # 3.不等式组对应的直线
        per_points = map(lambda line_eq: common_opers.perpendicular_line_and_foot(line_eq, circle_center)[1],
                         line_eqs)  # 4.求圆点到各个直线的垂足
        verify_per_points = filter(
            lambda per_point: common_opers.satisfied_ineqs(ineqs, (('x', per_point[0]), ('y', per_point[1]))),
            per_points)  # 5.保留满足不等式组的垂足
        # -------求圆心到各个直线的垂点及其距离-----------------
        verify_per_point_distances = map(
            lambda per_point: (per_point, common_opers.point_2_point_distance(circle_center, per_point)),
            verify_per_points)
        # verify_per_point_distances = map(lambda d: (zip(*d[0])[-1], d[1]), verify_per_point_distances)
        # verify_per_point_distances = map(lambda d: d[1] - r, verify_per_point_distances)  # 减去半径
        # --------求圆心到各个不等式组交点之间的距离----------------------------
        verify_inter_distances = map(
            lambda line_inter: (line_inter[1], common_opers.point_2_point_distance(circle_center,
                                                                                   map(lambda sv: sv[1],
                                                                                       line_inter[1]))),
            satisfied_inters)
        verify_inter_distances = map(lambda d: (zip(*d[0])[-1], d[1]), verify_inter_distances)
        # verify_inter_distances = map(lambda d: d[1] - r, verify_inter_distances)  # 减去半径

        # ----------求出所有距离的最小值-----------------------------------
        min_distance = min(chain(verify_per_point_distances, verify_inter_distances), key=lambda d: d[1])  # 最小值
        max_distance = max(chain(verify_per_point_distances, verify_inter_distances), key=lambda d: d[1])  # 最大值
        if text.find('最大值') >= 0 or text.find('最小值') >= 0:
            op, op_str = ('max', '最大值') if text.find('最大值') >= 0 else ('min', '最小值')
            op_value = common_opers.expr_subs(circle_expr,
                                              zip(symbs, max_distance[0])) if op == 'max' else common_opers.expr_subs(
                circle_expr, zip(symbs, min_distance[0]))
            # ---------------------------输出---------------------------
            self.steps.append(['由约束条件:' + ineqs_printing, ''])
            self.steps.append(
                ['由条件可知: %s 的 %s ' % (new_latex(circle_expr), op_str),
                 '; 即为点到圆心: %s 的 %s' % (new_latex(circle_center), op_str)])
            self.steps.append(['%s为' % op_str, new_latex(op_value)])
            # self.output.append(BaseNumber(op_value))
            # self.output.append(BaseSymbolValue({sympify(z_sy): op_value}))
            self.output.append(BaseNumber(op_value))
            return self
        else:
            op, op_str = ('max', '最大值')
            op_value = common_opers.expr_subs(circle_expr,
                                              zip(symbs, max_distance[0])) if op == 'max' else common_opers.expr_subs(
                circle_expr, zip(symbs, min_distance[0]))
            # ---------------------------最大输出---------------------------
            self.steps.append(['由约束条件:' + ineqs_printing, ''])
            self.steps.append(
                ['由条件可知: %s 的 %s ' % (new_latex(circle_expr), op_str),
                 '; 即为点到圆心: %s 的 %s' % (new_latex(circle_center), op_str)])
            self.steps.append(['%s为' % op_str, new_latex(op_value)])
            max_value = op_value
            # ---------------------------------------------------------------
            op, op_str = ('min', '最小值')
            op_value = common_opers.expr_subs(circle_expr,
                                              zip(symbs, max_distance[0])) if op == 'max' else common_opers.expr_subs(
                circle_expr, zip(symbs, min_distance[0]))
            # ---------------------------最小输出---------------------------
            self.steps.append(['由约束条件:' + ineqs_printing, ''])
            self.steps.append(
                ['由条件可知: %s 的 %s ' % (new_latex(circle_expr), op_str),
                 '; 即为点到圆心: %s 的 %s' % (new_latex(circle_center), op_str)])
            self.steps.append(['%s为' % op_str, new_latex(op_value)])
            min_value = op_value
            result = Interval(min_value, max_value)
            self.steps.append(['所以' + new_latex(circle_expr), ' 取值范围为:' + new_latex(result)])
            # self.output.append(common_opers.to_base_interval(result))
            # self.output.append(BaseSymbolValue({sympify(z_sy): result}))
            self.output.append(common_opers.to_base_interval(result))
            return self


# 3.最优解不唯一
class OptimalSolution001(BaseFunction):
    def solver(self, *args):
        self.label.add('线性规划最优解不唯一')
        ineqs = args[0].sympify()
        target_e = args[1]  # 目标表达式
        optimum = args[2]  # 最优解是最大值还是最小值
        a_symbol = 'a'  # 要求的符号
        ineqs_symbs = common_opers.ineqs_symbs(ineqs)
        if len(ineqs_symbs) > 2:
            raise Exception('Type Match Error')
        eqs = common_opers.ineqs_2_eqs(ineqs)
        optimum_func = max if optimum == 'max' else min
        # 1.把约束条件中各个直线的斜率求出 k1,k2,k3
        line_slopes = map(common_opers.line_slope, common_opers.to_base_list(eqs))
        line_slopes = filter(lambda slope: slope, line_slopes)
        # simply_target_eq = common_opers.simplify_line_eq(args[1])
        # 2.求出满足不等式的顶点A1,A2,A3
        # inters = map(lambda two_ineq_point: two_ineq_point[1], common_opers.ineqs_intersections(ineqs))
        inters = map(lambda two_ineq_point: two_ineq_point[1], common_opers.satisfied_ineqs_intersections(ineqs))
        optimum_k_and_value_list = []
        # 3.令a=k in (k1, k2, k3), 且 max/min(A1，A2，A3...)使的目标函数取值的Ai满足直线Y=kiX+B则。 a保留
        for k in line_slopes:
            # 把目标函数整理成y=kx+b的形式
            z_symbol, simply_target_expr = common_opers.line_slope_inter_eq(target_e, y_symbol='z').sympify()
            # 目标函数 z = -a*x + y 或者 z = a*x + b*y, 把 a 替换成k的值(只替换a的值,不管a前面的正负性)
            simply_target_eq = BaseEq(
                [z_symbol, simply_target_expr.subs(a_symbol, k)])
            current_point_values = map(lambda inter: common_opers.expr_subs(simply_target_eq.sympify()[1], inter),
                                       inters)  # a=k的时候 z 的值。
            optimum_value = optimum_func(current_point_values)
            other_optimum_values = filter(lambda point_value: point_value == optimum_value, current_point_values)
            if len(other_optimum_values) > 1:
                optimum_k_and_value_list.append((k, optimum_value))
        optimum_k_and_value = optimum_func(optimum_k_and_value_list, key=lambda k_and_value: k_and_value[1])
        optimum_k_and_values = filter(lambda k_and_value: k_and_value[1] == optimum_k_and_value[1],
                                      optimum_k_and_value_list)
        self.steps.append(['最优解不唯一', optimum_k_and_values])
        return self


# 4.最优解唯一(最大或者最小)
#           Input:  不等式组,目标表达式,最大(最小)值坐标.
#           Output: 目标表达式中未知参数的取值范围
class OptimalSolution(BaseFunction):
    def solver(self, *args):
        self.label.add('线性规划最优解唯一')
        ineqs_printing = args[0].printing()
        ineqs = args[0].sympify()
        ineqs_symbols = common_opers.ineqs_symbs(ineqs)
        if len(ineqs_symbols) > 2:
            raise Exception('Type Match Error')
        target_e = args[1]
        target_slope_eq = common_opers.line_slope_inter_eq(target_e)  # 化成形如y = k*x + b
        z_symbol, f = args[1].sympify()
        optimum_value_point = args[2].sympify()
        optimum = 'max' if args[3].find('最大值') >= 0 else 'min'
        ineq_op = '<' if optimum == 'max' else '>'
        optimum_value = common_opers.expr_subs(f, zip(('x', 'y'), optimum_value_point))
        # 1. 所有满足约束条件的顶点 A, B, C
        satisfied_ineqs_inters = common_opers.satisfied_ineqs_intersections(ineqs)
        other_points = filter(lambda point: not optimum_value_point == point,
                              map(lambda inter: zip(*inter[1])[1], satisfied_ineqs_inters))
        other_f_values = map(lambda point: common_opers.expr_subs(f, zip(('x', 'y'), point)), other_points)
        new_ineqs = common_opers.to_bases(
            map(lambda point_value: BaseIneq([point_value, ineq_op, optimum_value]), other_f_values), BaseIneqs)
        stepsolver = FangChenBuDengShi002(verbose=True).solver(new_ineqs)
        result_root = stepsolver.output[0].value
        self.steps.append(['由x,y满足约束条件:', ineqs_printing])
        self.steps.append(['画出可行域:', ''])
        self.steps.append(['由于目标函数为:' + target_e.printing(), '得到:' + target_slope_eq.printing()])
        slope = common_opers.line_slope(target_slope_eq)
        self.steps.append(['由该式子斜率为' + str(slope),
                           '并且随着%s的值变化而变化,由因为%s的最优解恰为:%s' % (
                               str(slope), target_e.printing(), optimum_value_point)])
        self.steps.append(
            ['所以可知当目标函数代表的直线介于直线L1与L2之间时才能使得%s取得的最优解恰为:%s' % (target_e.printing(), optimum_value_point), ''])
        self.steps.append(['所以a的取值范围', result_root.values()[0]])
        # self.output.append(BaseSymbolValue({sympify('a'): result_root}))
        self.output.append(common_opers.to_base_interval(result_root.values()[0]))

        return self


# 5.最优解(OK)
#              Input: 不等式组,目标表达式
#             Output: 最优解对应的坐标,或者线段
class OptimalSolutionPoint(BaseFunction):
    def solver(self, *args):
        self.label.add('线性规划最优解')
        ineqs_printing = args[0].printing()
        ineqs = args[0].sympify()
        ineqs_symbols = common_opers.ineqs_symbs(ineqs)
        if len(ineqs_symbols) > 2:
            raise Exception('Type Match Error')
        target_e = args[1]
        z_symbol, f = args[1].sympify()
        # 1.求出满足约束条件的顶点
        satisfied__ineqs_inters = common_opers.satisfied_ineqs_intersections(ineqs)
        # f_values = map(lambda inter:inter[1],satisfied__ineqs_inters)
        points = map(lambda inter: zip(*inter[1])[1], satisfied__ineqs_inters)
        # 2.求各个顶点对应的目标表达式的值
        f_values = map(lambda point: (point, common_opers.expr_subs(f, zip(('x', 'y'), point))), points)
        max_point_value = max(f_values, key=lambda point_and_value: point_and_value[1])
        max_point_size = len(filter(lambda point_value: point_value[1] == max_point_value[1], f_values))
        if max_point_size > 1:
            max_os = BaseEq([f, max_point_value[1]])
        else:
            max_os = max_point_value[1]
        min_point_value = min(f_values, key=lambda point_and_value: point_and_value[1])
        min_point_size = len(filter(lambda point_value: point_value[1] == min_point_value[1], f_values))
        if min_point_size > 1:
            min_os = BaseEq([f, min_point_value[1]])
        else:
            min_os = min_point_value[1]

        # -----------输出--------------------
        self.steps.append(['由可行域:', ineqs_printing])
        self.steps.append(
            ['目标函数:%s。' % target_e.printing(), '得:' + common_opers.line_slope_inter_eq(target_e).printing()])
        slope = common_opers.line_slope(target_e)
        self.steps.append(['做y=%sx的平行线:' % slope, ''])
        self.steps.append(
            ['取最小值时,最优解为:', '线段:' + min_os.printing() if isinstance(min_os, BaseValue) else '' + str(min_os)])
        self.steps.append(
            ['取最大值时,最优解为:', '线段:' + max_os.printing() if isinstance(max_os, BaseValue) else '' + str(max_os)])
        # self.output.append([min_os, max_os])
        # self.output.append(BaseSymbolValue({sympify(z_symbol): Interval(min_os, max_os)}))
        self.output.append(common_opers.to_base_interval(Interval(min_os, max_os)))
        # print min_point_value, max_point_value
        return self


# 6.斜率型的最值问题 (OK)
class SlopeOptimalSolution(BaseFunction):
    @staticmethod
    def find_ineqs(src_ineqs):
        target_ineqs_list = []
        ineqs_list = src_ineqs.sympify()
        ineqs_symbols = common_opers.ineqs_symbs(ineqs_list)
        if len(ineqs_symbols) > 2:
            raise Exception('Type Match Error')
        for ineq in ineqs_list:
            if len(ineq) == 5:  # 形如 3 <= x <= 5的形式
                target_ineqs_list.append([ineq[2], common_opers.reverse_ineq_op(ineq[1]), ineq[0]])
                target_ineqs_list.append([ineq[2], common_opers.reverse_ineq_op(ineq[3]), ineq[4]])
            else:
                left, ineq_op, right = BaseEq(ineq).sympify()  # 约定left表示表达式, right表示常数(如果不是，则变换一下方向)
                if left.is_real:
                    left, ineq_op, right = right, ineq_op.replace('>', '<') if ineq_op.find(
                        '>') >= 0 else ineq_op.replace('<', '>'), left
                tmp_f = expand(left - right)
                tmp_fac = factor(tmp_f)
                fac1, fac2 = tmp_fac.args
                if isinstance(tmp_fac,
                              Mul) and not fac1.is_real and not fac2.is_real:  # 形如 (x + y - 5)*(3*x + 6 - 10) >= 0
                    target_ineqs_list.append([fac1, ineq_op, 0])
                    target_ineqs_list.append([fac2, ineq_op, 0])
                elif isinstance(left, Abs):
                    e = left.args[0]
                    target_ineqs_list.append([e, ineq_op, right])
                    target_ineqs_list.append([e, common_opers.reverse_ineq_op(ineq_op), -right])
                else:
                    target_ineqs_list.append([left, ineq_op, right])
        return target_ineqs_list

    def solver(self, *args):
        self.label.add('线性规划斜率型')
        ineqs = args[0]
        ineqs_list = ineqs.sympify()
        ineqs = common_opers.simp_ineqs(ineqs)
        ineqs_str = ''.join(map(lambda ineq: ''.join(map(str, ineq)), ineqs_list))
        ineqs_letters = common_opers.str_letters(ineqs_str)
        if isinstance(args[1], BasePoly):
            target_eq = BaseEq(['z', args[1].sympify()])
            target_symb = 'z'
            self.steps.append(['令 z = %s' % new_latex(args[1].sympify()), '.'])
        else:
            eq_symbs = common_opers.str_letters(str(common_opers.eq_2_f(args[1])))
            try:
                target_symb = str(list(set(ineqs_letters) - set(eq_symbs))[0])
            except Exception:
                target_symb = str(list(set(eq_symbs) - set(ineqs_letters))[0])
            target_eq = args[1]
        target_text = args[-1] if isinstance(args[-1], str) else str(args[-1])
        # 1.把目标函数整理成y-b=K(x-a)的形式
        # target_e_vertex_eq = common_opers.line_point_slope_eq(target_eq, k_symbol='s')
        _, t_expr = target_eq.sympify()
        if len(t_expr.free_symbols) > 2:
            raise Exception('Can not solve paramer expr')
        target_e_vertex_eq = common_opers.line_point_slope_eq(target_eq, k_symbol=target_symb)
        target_e_k = common_opers.line_slope(target_eq)
        # 2.求出(a, b)坐标。
        a, b = common_opers.slope_vertex_point(target_eq, k_symbol=target_symb)
        # 2.求出满足条件的可行域的顶点。
        # new_ineqs = common_opers.simp_ineqs(args[0])
        inter_points = common_opers.satisfied_ineqs_intersections(ineqs)
        # 3.依次计算顶点与（a,b）之间的斜率。
        slopes = map(
            lambda inter_point: (inter_point[0], common_opers.two_point_line_slope(zip(*inter_point[1])[1], (a, b))),
            inter_points)
        slopes = map(lambda s: (s[0], solve(target_e_k - s[1])[0]), slopes)
        eqs = common_opers.to_base_list(common_opers.ineqs_2_eqs(ineqs))  # 不等式组对应的直线
        # eqs = common_opers.to_base_list(common_opers.ineqs_2_eqs(new_ineqs))  # 不等式组对应的直线
        x_a_line = BaseEq(['x', a])  # x=a的直线
        y_b_line = BaseEq(['y', b])  # y=b的直线
        a_inters_lines = filter(lambda eq: common_opers.two_lines_have_intersections([x_a_line, eq]),
                                eqs)  # 过滤掉与直线x=a没有交点的直线
        a_slope_inters = map(lambda eq: common_opers.lines_intersections([x_a_line, eq])[0][1],
                             a_inters_lines)  # x=a与等式直线的交点
        a_slope_inters = filter(lambda inter: common_opers.satisfied_ineqs(ineqs, inter),
                                a_slope_inters)  # x=a直线与不等式组交点是否满足不等式组
        b_inters_lines = filter(lambda eq: common_opers.two_lines_have_intersections([y_b_line, eq]),
                                eqs)  # 过滤掉与直线y=b没有交点的直线
        b_slope_inters = map(lambda eq: common_opers.lines_intersections([eq, y_b_line])[0][1],
                             b_inters_lines)  # y=b与不等式直线的交点
        b_slope_inters = filter(lambda inter: common_opers.satisfied_ineqs(ineqs, inter),
                                b_slope_inters)  # y=b 直线与不等式组交点是否满足不等式组

        def interv_opened(two_ineqs):
            return two_ineqs[0][1] in ['<', '>'] or two_ineqs[1][1] in ['<', '>']

        target_interval = None
        if not a_slope_inters and not b_slope_inters:  # 如果(a, b)与顶点都没有交点的话。那么k的取值范围为 (min(slopes), max(slopes))
            min_point_value = min(slopes, key=lambda inter_point: inter_point[1])  # 斜率最小值
            max_point_value = max(slopes, key=lambda inter_point: inter_point[1])  # 斜率最大值
            target_interval = Interval(min_point_value[1], max_point_value[1],
                                       left_open=interv_opened(min_point_value[0]),
                                       right_open=interv_opened(max_point_value[0]))
        elif a_slope_inters and not b_slope_inters:
            # 如果与x=a有交点与y=b没有交点的话。那么k的取值范围为 (min(slopes >0), +oo)U(-oo, max(slopes<0))
            positive_min = min(filter(lambda s: s[1] > 0, slopes), key=lambda s: s[1])
            positive_interval = Interval(positive_min[1], S.Infinity,
                                         left_open=interv_opened(positive_min[0]),
                                         right_open=True)
            negatives = filter(lambda s: s[1] < 0, slopes)
            if negatives:
                negative_max = max(negatives, key=lambda s: s[1])
                negative_interval = Interval(-S.Infinity, negative_max[1], left_open=True,
                                             right_open=interv_opened(negative_max[0]))
                target_interval = positive_interval.union(negative_interval)
            else:
                target_interval = positive_interval
        elif not a_slope_inters and b_slope_inters:
            # 如果与x=a没有交点与y=b有交点,那么k的取值范围为 (min(slopes), max(slopes))
            min_point_value = min(slopes, key=lambda inter_point: inter_point[1])  # 斜率最小值
            max_point_value = max(slopes, key=lambda inter_point: inter_point[1])  # 斜率最大值
            target_interval = Interval(min_point_value[1], max_point_value[1],
                                       left_open=interv_opened(min_point_value[0]),
                                       right_open=interv_opened(max_point_value[0]))
        elif a_slope_inters and b_slope_inters:
            target_interval = Interval(-S.Infinity, S.Infinity, left_open=True, right_open=True)

        # --------输出-------------------------
        self.steps.append(['先画出x, y满足' + ineqs.printing(), '表示的平面区域,'])
        self.steps.append(['目标函数整理成:', target_e_vertex_eq.printing()])
        self.steps.append(['根据目标函数:' + target_e_vertex_eq.printing(), '的几何意义'])
        self.steps.append([new_latex(target_e_k), '表示区域里的点(x, y)与(%s, %s)连线的斜率,' % (a, b)])
        if target_text.find('最大值') >= 0:
            self.steps.append(['\\therefore ', '%s 最大值为: %s' % (new_latex(target_symb), new_latex(target_interval.right))])
            # self.output.append(BaseSymbolValue({sympify(target_symb): target_interval.right}))
            self.output.append(BaseNumber(target_interval.right))
        elif target_text.find('最小值') >= 0:
            self.steps.append(['\\therefore ', '%s 最小值为: %s' % (new_latex(target_symb), new_latex(target_interval.left))])
            # self.output.append(BaseSymbolValue({sympify(target_symb): target_interval.left}))
            self.output.append(BaseNumber(target_interval.left))
        else:
            self.steps.append(['可得要求的范围为:', new_latex(target_interval)])
            self.output.append(BaseSymbolValue({sympify(target_symb): target_interval}))
            # self.output.append(common_opers.to_base_interval(target_interval))
        return self


class XianXingGuiHua(BaseFunction):
    @staticmethod
    def target_f(target_e):
        if isinstance(target_e, BaseEq):
            f = common_opers.eq_2_f(target_e)
        else:
            f = target_e.sympify()
        return f

    # 线性约束条件，线性目标函数的范围问题
    # 已知实数x,y满足\\left\\{\\begin{array}{c}x+y-3≥0\\\\x+2y-5≤0\\\\x≥0\\\\y≥0\\end{array}\\right.,则y-2x的最大值是().
    @staticmethod
    def class_001(target_e):
        f = XianXingGuiHua.target_f(target_e)
        f_deg = degree_list(f)
        symbs = list(sorted(map(str, f.free_symbols)))
        x_symbol = symbs[0] if str(symbs[0]) != 'y' else 'x'
        y_symbol = symbs[1] if len(symbs) == 2 else 'y'
        line_k = sympify(common_opers.line_slope(BaseEq([f, 0]), x_symbol=x_symbol, y_symbol=y_symbol))
        return max(f_deg) == 1 and line_k != 0 and line_k.is_real

    # 可行域内的点与圆上的点的距离型最值
    # 已知实数x,y满足\\left\\{\\begin{array}{c}y≥1\\\\x+y-4≤0\\\\x-y≥0\\end{array}\\right.,则x^{2}+y^{2}+4x+6y+14的最大值为()
    @staticmethod
    def class_002(target_e):
        def sqrt_arg(tmp_f):  # 获取含有根号的表达式中 是否含有x**2 + y**2
            d = common_opers.coefficients_dict(tmp_f)
            sqrt_term = list(filter(lambda i: isinstance(i[0], Pow), d.items()))
            if sqrt_term:
                st = sqrt_term[0]
                if st[0].args[1] == sympify('1/2'):
                    return st[0].args[0]
            return None

        f = XianXingGuiHua.target_f(target_e)
        if sqrt_arg(f):
            sa = sqrt_arg(f)
            if degree(sa) == 2:
                return True
        f_deg = degree_list(f)
        if max(f_deg) == 2:
            return True
        else:
            return False

    # 6.斜率型的最值问题
    # 实数x,y满足\\left\\{\\begin{array}{c}(x-y+6)(x+y-6)≥0\\\\1≤x≤4\\end{array}\\right.,则\\frac{y}{x}的最大值是()
    # x,y满足\left\{\begin{array}{c}|x-y|≤1\\4≤x+2y\end{array}\right.,则\frac{y}{x+2}的取值范围是.
    @staticmethod
    def class_006(target_e):
        f = XianXingGuiHua.target_f(target_e)
        f_deg = degree_list(f)
        line_k = sympify(common_opers.line_slope(BaseEq([f, 0])))  # 斜率等于0的情况就是 形如f(y)/g(x) = 0的形式
        return max(f_deg) == 1 and (line_k == 0 or not line_k.is_real)

    def solver(self, *args):
        quest_text = args[-1]
        ineqs = args[0]
        target_e = args[1]
        # ---------log处理--------------
        # tmp_eq = BaseEq([target_e.sympify(), 0])
        # cond = common_opers.log_ded_eq(tmp_eq)  # -------log判断---------------
        # if tmp_eq != cond:
        #     pass
        # ---------log处理--------------
        if XianXingGuiHua.class_001(target_e):
            return LinearProgramming(verbose=True).solver(ineqs, target_e, quest_text)
        elif XianXingGuiHua.class_002(target_e):
            return XianXingGuiHhua001(verbose=True).solver(ineqs, target_e, quest_text)
        elif XianXingGuiHua.class_006(target_e):
            return SlopeOptimalSolution(verbose=True).solver(ineqs, target_e, quest_text)
        return self


if __name__ == '__main__':
    pass
